import {AntiJitter, guid} from '@/utils';
import Constants from '@comp/FormEngine/Constants';
import {postAction} from '@/request';
import $ from 'jquery';
import { showFailToast } from 'vant';
import {AuthType} from '@comp/FormEngine/Constants';

let antj = null
let changedFields = []
let changedRowIds = []

export default class FormEngineContext {
  props = undefined;
  emits = undefined;

  formDefinition = undefined;
  formModel = undefined;
  actionId = undefined;
  viewId = undefined;
  forceDetail = undefined;
  formNameSpace = undefined;

  view = undefined;
  action = undefined;
  templateConfigs = [];
  focusData;
  manualAuth = {};
  openRelationFormModelPop = undefined;
  formWrapper = undefined;

  constructor({props, emits, manualAuth, formWrapper,
                openRelationFormModelPop}) {
    this.props = props;
    this.formWrapper = formWrapper;
    this.emits = emits;
    this.manualAuth = manualAuth;
    this.openRelationFormModelPop = openRelationFormModelPop

    this.formDefinition = props.formDefinition;
    this.formModel = props.modelValue;
    this.actionId = props.action;
    this.viewId = props.view;
    this.forceDetail = props.forceDetail;
    this.formNameSpace = guid();
    if (!this.formModel) this.initIfNecessary();
  }

  initIfNecessary() {
    this.view = this.formDefinition.views.find(v => v.id === this.viewId);
    this.action = this.formDefinition.actions.find(a => a.id === this.actionId);
    this.templateConfigs = this.view && this.view.templateConfigs || undefined;

    this.buildModelIfNecessary();
  }

  showLabel() {
    try {
      let view = this.getCurrentView();
      return view.mobileView
    } catch (e) {}
    return true
  }

  getFormWrapperStyle() {
    let view = this.getCurrentView();
    if (view.mobileView) {
      //当前是移动端视图
      return  {}
    } else {
      //当前是pc视图
      return  {
        backgroundColor: 'white',
        width: `${this.getCurrentView().pageWidth}px`,
        transformOrigin: 'top left',
      }
    }
  }

  isMobileView() {
    try {
      return this.getCurrentView().mobileView
    } catch(e) {
      console.error(e)
    }
    return false;
  }

  getCurrentView() {
    let views = this.formDefinition.views;
    return views.find(v => v.id === this.viewId);
  }

  buildModelIfNecessary() {
    if (!this.formModel) return

    this.buildMainFields();
    this.buildSubFormFields();
    this.buildMainAuthFields();
    this.buildSubAuthFields();
    this.buildSubFormAuthFields();
    this.buildAttachmentFields();
    this.buildHiddenBlocks();
    this.buildManualAuth();
    this.buildViewRedirect();
  }

  buildMainAuthFields() {
    this.doBuildAuthFields(this.formModel, this.formDefinition);
    this.doBuildRequiredFields(this.formModel, this.formDefinition);
  }

  buildSubAuthFields() {
    let subForms = this.formDefinition.subForms || [];
    subForms.forEach(subForm => {
      let subFormModels = this.formModel[subForm.id] || [];
      subFormModels.forEach(subFormModel => {
        this.doBuildAuthFields(subFormModel, subForm);
        this.doBuildRequiredFields(subFormModel, subForm);
      });
    });
  }

  buildSubFormAuthFields() {
    let subForms = this.formDefinition.subForms || [];
    let subFormAuth = this.formModel[Constants.subFormAuthFieldName] || {};
    this.formModel[Constants.subFormAuthFieldName] = subFormAuth
    let subFormActions = this.action && this.action.subFormActions || [];
    subForms.forEach(subForm => {
      let authObj = subFormAuth[subForm.id] || {};
      let subFormAction = subFormActions.find(s => s.subFormId === subForm.id) || {};
      !authObj.hasOwnProperty('addRow') && (authObj.addRow = !!subFormAction.addRow);
      !authObj.hasOwnProperty('copyRow') && (authObj.copyRow = !!subFormAction.copyRow);
      !authObj.hasOwnProperty('removeRow') && (authObj.removeRow = !!subFormAction.removeRow);
      !authObj.hasOwnProperty('clearRow') && (authObj.clearRow = !!subFormAction.clearRow);
      !authObj.hasOwnProperty('moveUp') && (authObj.moveUp = !!subFormAction.moveUp);
      !authObj.hasOwnProperty('moveDown') && (authObj.moveDown = !!subFormAction.moveDown);
      subFormAuth[subForm.id] = authObj;
    });
  }

  buildAttachmentFields() {
    let attachmentObj = this.formModel._attachment || {}
    this.formModel._attachment = attachmentObj;

    let attachments = attachmentObj.attachments || [];
    let attachmentRelations = attachmentObj.attachmentRelations || [];

    attachmentObj.attachments = attachments;
    attachmentObj.attachmentRelations = attachmentRelations;
  }

  buildHiddenBlocks() {
    let hideBlocks = this.formModel._hideBlocks || {};
    (this.templateConfigs || []).forEach((templateConfig) => {
      let blockContainerId = templateConfig.blockContainerId
      if (blockContainerId) {
        hideBlocks[blockContainerId] = hideBlocks[blockContainerId] || false;
      }
    })
    this.formModel._hideBlocks = hideBlocks;
  }

  buildManualAuth() {
    let manualAuth = this.formModel._manualAuth || {};
    (this.formDefinition && this.formDefinition.relations || []).forEach(relation => {
      (relation && relation.manuals || []).forEach(manual => {
        manual.id && (manualAuth[manual.id] = manualAuth[manual.id] || this.manualAuth[manual.id] || false);
      })
    })
    this.formModel._manualAuth = manualAuth;
  }

  buildViewRedirect() {
    let viewRedirect = this.formModel._viewRedirect
    if (!viewRedirect) {
      this.formModel._viewRedirect = viewRedirect = {};
    }
    (this.formDefinition.views || []).forEach(v => {
      viewRedirect[v.id] = viewRedirect[v.id] || undefined;
    })
  }


  doBuildAuthFields(model, formDefinition) {
    let auth = model[Constants.authFieldName] || {};
    let fields = formDefinition && formDefinition.fields || [];
    fields.forEach(f => {
      let fieldActions = this.action && this.action.fieldActions || [];
      let fieldAuth = 'edit';
      fieldActions.forEach(fa => {
        if (fa.fieldId === f.id) {
          fieldAuth = fa.auth;
        }
      });
      auth[f.fieldName] = auth[f.fieldName] || fieldAuth || 'edit';
    });
    model[Constants.authFieldName] = auth;
  }

  doBuildRequiredFields(model, formDefinition) {
    let required = model[Constants.requiredFieldName] || {};
    let fields = formDefinition && formDefinition.fields || [];
    fields.forEach(f => {
      let fieldActions = this.action && this.action.fieldActions || [];
      let fieldRequired = false;
      fieldActions.forEach(fa => {
        if (fa.fieldId === f.id) fieldRequired = fa.required;
      });
      required[f.fieldName] = this.resolveFieldRequired(required[f.fieldName], fieldRequired, false);
    });
    model[Constants.requiredFieldName] = required;
  }

  resolveFieldRequired(originRequired, defaultRequired, systemDefaultRequired) {
    if (originRequired !== null && originRequired !== undefined) return originRequired;
    if (defaultRequired !== null && defaultRequired !== undefined) return defaultRequired;
    return systemDefaultRequired;
  }

  buildMainFields() {
    this.buildFields(this.formDefinition, this.formModel);
  }

  buildSubFormFields() {
    let subForms = this.formDefinition.subForms || [], model = this.formModel;
    subForms.forEach(subForm => {
      let subFormDataSource = model[subForm.id] || this.buildSubFormRows(subForm);
      model[subForm.id] = subFormDataSource;
      subFormDataSource.forEach(item => {
        this.buildFields(subForm, item);
      });
    });
  }

  buildSubFormRows(subForm) {
    let res = [];
    let initRows = subForm.initRows || 0;
    for (let i = 0; i < initRows; i++) {
      res.push({
        id: guid(),
        _initedEmptyField: false,
        _isNew: true
      });
    }
    return res;
  }


  buildFields({fields}, model) {
    fields = fields || [];
    fields.forEach(f => {
      model[f.fieldName] = model[f.fieldName] || undefined;
      f.fieldTitleName && (model[f.fieldTitleName] = model[f.fieldTitleName] || undefined);
    });
  }

  changeFormModel(formModel) {
    window.updateCount = window.updateCount || 1;
    ++window.updateCount;

    if (this.formModel) {
      Object.assign(this.formModel, formModel);
    } else {
      this.emits('update:modelValue', formModel);
    }
  }

  check() {
    return !!this.view && !!this.view && !!this.view.templateConfigs;
  }

  updateSubFormData() {
    this.formFieldUpdate();
  }

  formFieldUpdate(fieldConfig, rowId) {
    if (fieldConfig) {
      changedFields.push(fieldConfig);
      changedRowIds.push(rowId || ' ');
    }

    antj = antj || new AntiJitter(() => this.doFormFieldUpdate(fieldConfig, rowId), 10)
    antj.invoke()
  }

  doFormFieldUpdate(fieldConfig, rowId) {
    if(!this.formModel || !this.formDefinition || !this.formDefinition.fields || !this.formDefinition.fields.length) return
    if (this.formModel && this.formModel._firstLoaded) return this.formModel._firstLoaded = false
    if (!window.updateCount) window.updateCount = 1;
    let tempUpdateCount = ++window.updateCount;
    let fieldId = changedFields.map(item => item.id).join(',')
    let hisData = JSON.parse(JSON.stringify(this.formModel || {}));
    this.formModel = this.props.modelValue;

    postAction('/form/formFieldUpdate', {
      rowId: changedRowIds.join(','),
      actionId: this.actionId,
      fieldId,
      formModel: this.formModel,
      formDefinitionId: this.formDefinition.id
    }).then(({result}) => {
      antj = null
      changedRowIds = []
      changedFields = []
      if(result && (tempUpdateCount === window.updateCount)) {
        this.updateAutoRelation(result, tempUpdateCount, fieldId, hisData);
      }
    }).catch(e => {
      antj = null
      changedRowIds = []
      changedFields = []
      console.error(e);
    });
  }

  updateAutoRelation(formModel, tempUpdateCount, fieldId, hisData) {
    if(!this.formDefinition || !this.formDefinition.fields || !this.formDefinition.fields.length) return
    let actionId = this.actionId;
    let viewId = this.viewId;
    this.formModel = this.props.modelValue;
    postAction('/form/autoRelation', {
      formModel,
      actionId,
      fieldIds: [fieldId],
      viewId,
      formDefinitionId: this.formDefinition.id
    }).then(({result}) => {
      (tempUpdateCount === window.updateCount) && result && this.patchFormModel(result, hisData);
      ++window.updateCount;
    }).catch(console.error);
  }

  patchFormModel(changedData, hisData) {
    if (this.focusData) {
      let fieldConfig = this.focusData.fieldConfig;
      if (!this.focusData.rowId) {
        //主表
        changedData[fieldConfig.fieldName] = this.formModel[fieldConfig.fieldName];
      } else {
        //明细表
        try {
          let rowIndex = this.focusData.rowIndex;
          changedData[fieldConfig.formId][rowIndex][fieldConfig.fieldName] = this.formModel[fieldConfig.formId][rowIndex][fieldConfig.fieldName]
        } catch (e) {
          console.log(e)
        }
      }
    }
    this.changeFormModel(changedData);
  }

  initFormData(callback) {
    if(!this.formDefinition || !this.formDefinition.fields || !this.formDefinition.fields.length) return
    if (!this.formDefinition.id || !this.formDefinition || !this.actionId) {
      return
    }

    this.formModel = this.props.modelValue
    postAction('/form/initFormData', {
      formDefinitionId: this.formDefinition.id,
      actionId: this.actionId
    }).then(({ result }) => {
      if (!this.formModel || !this.formModel.id) {
        if (this.formModel === this.props.modelValue) {
          this.changeFormModel(result || {});
        }
      }
      callback && callback()
    }, error => {
      if (!this.formModel || !this.formModel.id)
        this.changeFormModel(result || {})
      callback && callback()
    }).catch(e => {
      if (!this.formModel || !this.formModel.id)
        this.changeFormModel(result || {})
      callback && callback()
    })
  }

  openRelationForm(data) {
    this.openRelationFormModelPop(data);
  }

  checkFormData() {
    return new Promise((success, err) => {
      let promises = [
        () => this.checkRequired(),
        () => this.chechRules()
      ];

      function deep(promises, index = 0) {
        promises.length === index + 1 ? promises[index]().then(success).catch(err || console.error) :
          promises[index]().then(() => deep(promises, index + 1)).catch(err || console.error);
      }

      deep(promises);
    });
  }

  checkRequired() {
    return new Promise((success, err) => {

      let fields = this.formDefinition.fields, required = this.formModel[Constants.requiredFieldName] || {};
      let auth = this.formModel[Constants.authFieldName] || {};
      for (let i = 0; i < fields.length; i++) {
        if (required[fields[i].fieldName] === true
          && this.showField(fields[i])
          && auth[fields[i].fieldName] === AuthType.edit
          && !this.formModel[fields[i].fieldName]
          && this.formModel[fields[i].fieldName] !== '0'
          && this.formModel[fields[i].fieldName] !== 0) {
          showFailToast({
            message: '请将必填项填写完整',
            allowMultipleToast: true
          });
          return err();
        }
      }

      let subForms = this.formDefinition.subForms || [];
      for (let i = 0; i < subForms.length; i++) {
        let subForm = subForms[i];
        fields = subForm.fields || [];
        let subFormDataSource = this.formModel[subForm.id] || [];
        for (let j = 0; j < subFormDataSource.length; j++) {
          for (let k = 0; k < fields.length; k++) {
            let field = fields[k];
            let subFormData = subFormDataSource[j];
            required = subFormData[Constants.requiredFieldName] || {};
            auth = subFormData[Constants.authFieldName] || {};
            if (required[field.fieldName] === true &&
              this.showField(fields[i]) &&
              auth[field.fieldName] === AuthType.edit &&
              !subFormData[field.fieldName]) {
              showFailToast({
                message: '请将必填项填写完整',
                allowMultipleToast: true
              });
              return err();
            }
          }
        }
      }

      success();
    });
  }

  chechRules() {
    return new Promise((success, err) => {
      let data = {formModel: this.formModel, actionId: this.actionId, formDefinitionId: this.formDefinition.id};
      postAction('/form/checkRules', data).then(data => {
        if (!data.success) {
          this.changeFormModel(data.result.formModel || this.formModel);
          showFailToast({
            message: data.message,
            allowMultipleToast: true
          });
          return err()
        }
        let { result } = data
        if (result && result.messages && result.messages.length) {
          return this.showCheckResultMessage(result.messages, () => success(this.formModel), err)
        }
        success(this.formModel)
      })
    });
  }

  showCheckResultMessage(messages, success, err) {
    //待开发
    success();
  }

  showField(field) {
    try {
      let fieldId = field.id;
      let eles = $(`[form-name-space='${this.formNameSpace}']`).find(`#${fieldId}`)
      if (eles && eles.length)
        return true
      eles = $(`[form-name-space='${this.formNameSpace}']`).find(`[relation-fake-field-id='${fieldId}']`)
      if (eles && eles.length)
        return true
    } catch (e) {
      console.log(e)
      return true;
    }
    return false
  }
}